package com.onlylemi.mapview.library.layer;


import com.onlylemi.mapview.library.MapView;
import com.onlylemi.mapview.library.ResourceTable;
import com.onlylemi.mapview.library.utils.MapUtils;
import ohos.agp.render.Arc;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.PixelMapHolder;
import ohos.agp.utils.Color;
import ohos.agp.utils.Matrix;
import ohos.agp.utils.Point;
import ohos.agp.utils.RectFloat;
import ohos.media.image.PixelMap;
import ohos.multimodalinput.event.TouchEvent;

/**
 * LocationLayer
 *
 * @author: onlylemi
 */
public class LocationLayer extends MapBaseLayer {

    private boolean openCompass = false;

    // compass color
    private static final int DEFAULT_LOCATION_COLOR = 0xFF3EBFC9;
    private static final int DEFAULT_LOCATION_SHADOW_COLOR = 0xFF909090;
    private static final int DEFAULT_INDICATOR_ARC_COLOR = 0xFFFA4A8D;
    private static final int DEFAULT_INDICATOR_CIRCLE_COLOR = 0xFF00F0FF;
    private static final float COMPASS_DELTA_ANGLE = 5.0f;
    private float defaultLocationCircleRadius;

    private float compassLineLength;
    private float compassLineWidth;
    private float compassLocationCircleRadius;
    private float compassRadius;
    private float compassArcWidth;
    private float compassIndicatorCircleRadius;
    private float compassIndicatorGap;
    private float compassIndicatorArrowRotateDegree;
    private float compassIndicatorCircleRotateDegree = 0;
    private PixelMap compassIndicatorArrowBitmap;

    private Paint compassLinePaint;
    private Paint locationPaint;
    private Paint indicatorCirclePaint;
    private Paint indicatorArcPaint;

    private Point currentPosition = null;

    public LocationLayer(MapView mapView) {
        this(mapView, null);
    }

    public LocationLayer(MapView mapView, Point currentPosition) {
        this(mapView, currentPosition, false);
    }

    public LocationLayer(MapView mapView, Point currentPosition, boolean openCompass) {
        super(mapView);
        this.currentPosition = currentPosition;
        this.openCompass = openCompass;

        level = LOCATION_LEVEL;
        initLayer();
    }

    private void initLayer() {
        // setting dufault values
        defaultLocationCircleRadius = setValue(8f);

        // default locationPaint
        locationPaint = new Paint();
        locationPaint.setAntiAlias(true);
        locationPaint.setStyle(Paint.Style.FILL_STYLE);
        locationPaint.setColor(new Color(DEFAULT_LOCATION_COLOR));

        compassRadius = setValue(38f);
        compassLocationCircleRadius = setValue(0.5f);
        compassLineWidth = setValue(1.3f);
        compassLineLength = setValue(2.3f);
        compassArcWidth = setValue(4.0f);
        compassIndicatorCircleRadius = setValue(2.6f);
        compassIndicatorGap = setValue(15.0f);

        // default compassLinePaint
        compassLinePaint = new Paint();
        compassLinePaint.setAntiAlias(true);
        compassLinePaint.setStrokeWidth(compassLineWidth);

        // default indicatorCirclePaint
        indicatorCirclePaint = new Paint();
        indicatorCirclePaint.setAntiAlias(true);
        indicatorCirclePaint.setStyle(Paint.Style.FILL_STYLE);
        indicatorCirclePaint.setColor(new Color(DEFAULT_INDICATOR_CIRCLE_COLOR));

        // default indicatorArcPaint
        indicatorArcPaint = new Paint();
        indicatorArcPaint.setStyle(Paint.Style.STROKE_STYLE);
        indicatorArcPaint.setColor(new Color(DEFAULT_INDICATOR_ARC_COLOR));
        indicatorArcPaint.setStrokeWidth(compassArcWidth);

        compassIndicatorArrowBitmap = MapUtils.getPixelMap(mapView.getContext(), ResourceTable.Media_compass);
    }

    @Override
    public void onTouch(TouchEvent event) {

    }

    @Override
    public void draw(Canvas canvas, Matrix currentMatrix, float currentZoom,
                     float currentRotateDegrees) {
        if (isVisible && currentPosition != null) {
            canvas.save();
            float[] goal = {currentPosition.getPointX(), currentPosition.getPointY()};
            currentMatrix.mapPoints(goal);

            canvas.drawCircle(goal[0], goal[1], defaultLocationCircleRadius,
                    locationPaint);

            canvas.drawCircle(goal[0], goal[1], defaultLocationCircleRadius,
                    locationPaint);

            if (openCompass) {
                for (int i = 0; i < 360 / COMPASS_DELTA_ANGLE; i++) {
                    canvas.save();
                    canvas.rotate(COMPASS_DELTA_ANGLE * i, goal[0], goal[1]);
                    if (i % (90 / COMPASS_DELTA_ANGLE) == 0) {
                        canvas.drawLine(goal[0], goal[1] - compassRadius
                                + compassLocationCircleRadius, goal[0], goal[1]
                                - compassRadius + compassLocationCircleRadius
                                - compassLineLength, compassLinePaint);
                    } else {
                        canvas.drawCircle(goal[0], goal[1] - compassRadius,
                                compassLocationCircleRadius, new Paint());
                    }
                    canvas.restore();
                }
                if (compassIndicatorArrowBitmap != null) {
                    canvas.save();
                    canvas.rotate(this.compassIndicatorArrowRotateDegree,
                            goal[0], goal[1]);
                    canvas.drawPixelMapHolder(new PixelMapHolder(compassIndicatorArrowBitmap), goal[0]
                                    - (float) compassIndicatorArrowBitmap.getImageInfo().size.width / 2,
                            goal[1] - defaultLocationCircleRadius
                                    - compassIndicatorGap, new Paint());
                    canvas.restore();
                    if (360 - (this.compassIndicatorArrowRotateDegree - this
                            .compassIndicatorCircleRotateDegree) > 180) {
                        canvas.drawArc(new RectFloat(goal[0] - compassRadius, goal[1]
                                - compassRadius, goal[0]
                                + compassRadius, goal[1]
                                + compassRadius), new Arc(-90 + this.compassIndicatorCircleRotateDegree,
                                this.compassIndicatorArrowRotateDegree - this
                                        .compassIndicatorCircleRotateDegree,
                                false), indicatorArcPaint);
                    } else {
                        canvas.drawArc(new RectFloat(goal[0] - compassRadius, goal[1]
                                - compassRadius, goal[0]
                                + compassRadius, goal[1]
                                + compassRadius), new Arc(-90 + this.compassIndicatorArrowRotateDegree,
                                360 - (this.compassIndicatorArrowRotateDegree - this
                                        .compassIndicatorCircleRotateDegree),
                                false), indicatorArcPaint);
                    }

                }
                canvas.save();
                canvas.rotate(compassIndicatorCircleRotateDegree, goal[0],
                        goal[1]);
                canvas.drawCircle(goal[0], goal[1] - compassRadius,
                        compassIndicatorCircleRadius, indicatorCirclePaint);
                canvas.restore();
            }
            canvas.restore();
        }
    }

    public boolean isOpenCompass() {
        return openCompass;
    }

    public void setOpenCompass(boolean openCompass) {
        this.openCompass = openCompass;
    }

    public Point getCurrentPosition() {
        return currentPosition;
    }

    public void setCurrentPosition(Point currentPosition) {
        this.currentPosition = currentPosition;
    }

    public float getCompassIndicatorCircleRotateDegree() {
        return compassIndicatorCircleRotateDegree;
    }

    public void setCompassIndicatorCircleRotateDegree(float compassIndicatorCircleRotateDegree) {
        this.compassIndicatorCircleRotateDegree = compassIndicatorCircleRotateDegree;
    }

    public float getCompassIndicatorArrowRotateDegree() {
        return compassIndicatorArrowRotateDegree;
    }

    public void setCompassIndicatorArrowRotateDegree(float compassIndicatorArrowRotateDegree) {
        this.compassIndicatorArrowRotateDegree = compassIndicatorArrowRotateDegree;
    }
}
